/**
 * HTTP请求拦截器 - 简化版
 * @description 统一处理API请求和响应，包括请求拦截、响应拦截、错误处理、认证token管理、错误重试、请求缓存等功能
 * @author 系统管理员
 * @version 2.0.0
 * @date 2024-01-15
 */

import { ElMessage, ElMessageBox } from 'element-plus'
import router from '@/router'
import { isLoggedIn, clearLoginStatus, isAdminLoggedIn, clearAdminLoginStatus } from './auth'

/**
 * 请求配置接口
 * @description 定义HTTP请求的配置参数，包括URL、方法、数据、参数、头部、超时、重试、缓存等选项
 */
interface RequestConfig {
  /** 请求URL */
  url: string
  /** HTTP请求方法，默认为GET */
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
  /** 请求体数据，用于POST、PUT、PATCH请求 */
  data?: any
  /** URL查询参数，会被拼接到URL中 */
  params?: any
  /** 自定义请求头 */
  headers?: Record<string, string>
  /** 请求超时时间（毫秒） */
  timeout?: number
  /** 是否显示全局加载状态，默认为true */
  showLoading?: boolean
  /** 是否显示错误消息，默认为true */
  showError?: boolean
  /** 重试次数，默认为3次 */
  retryCount?: number
  /** 重试延迟时间（毫秒），默认为1000ms */
  retryDelay?: number
  /** 是否启用缓存，GET请求默认为true */
  enableCache?: boolean
  /** 缓存过期时间（毫秒），默认为5分钟 */
  cacheExpiry?: number
  /** 自定义缓存键名 */
  cacheKey?: string
}

/**
 * API响应接口
 * @description 定义后端API返回的标准响应格式
 */
interface ApiResponse<T = any> {
  /** 响应状态码 */
  code: number
  /** 响应消息 */
  message: string
  /** 响应数据 */
  data: T
  /** 请求是否成功 */
  success: boolean
  /** 响应时间戳 */
  timestamp: number
}

/**
 * API错误接口
 * @description 定义API请求错误的标准格式
 */
interface ApiError {
  /** 错误状态码 */
  code: number
  /** 错误消息 */
  message: string
  /** 错误详情 */
  details?: any
  /** 错误时间戳 */
  timestamp: number
}

/**
 * 缓存项接口
 * @description 定义缓存数据的结构，包含数据、时间戳和过期时间
 */
interface CacheItem {
  /** 缓存的数据 */
  data: any
  /** 缓存创建时间戳 */
  timestamp: number
  /** 缓存过期时间（毫秒） */
  expiry: number
}

/**
 * API配置常量
 * @description 定义HTTP请求拦截器的全局配置，包括基础URL、默认参数、状态码映射、可重试错误类型等
 */
const API_CONFIG = {
  /** API基础URL，优先使用环境变量，默认为/api */
  BASE_URL: import.meta.env.VITE_API_BASE_URL || '/api',
  /** 默认请求超时时间（毫秒） */
  DEFAULT_TIMEOUT: 10000,
  /** 默认重试次数 */
  DEFAULT_RETRY_COUNT: 3,
  /** 默认重试延迟时间（毫秒） */
  DEFAULT_RETRY_DELAY: 1000,
  /** 默认缓存过期时间（毫秒），5分钟 */
  DEFAULT_CACHE_EXPIRY: 5 * 60 * 1000,
  /** 默认请求头 */
  HEADERS: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Requested-With': 'XMLHttpRequest'
  },
  /** HTTP状态码对应的错误消息 */
  STATUS_MESSAGES: {
    400: '请求参数错误',
    401: '未授权，请重新登录',
    403: '禁止访问',
    404: '请求的资源不存在',
    405: '请求方法不允许',
    408: '请求超时',
    429: '请求过于频繁',
    500: '服务器内部错误',
    502: '网关错误',
    503: '服务不可用',
    504: '网关超时'
  },
  /** 可重试的HTTP状态码列表 */
  RETRYABLE_STATUS_CODES: [408, 429, 500, 502, 503, 504],
  /** 可重试的网络错误类型 */
  NETWORK_ERROR_TYPES: ['TypeError', 'NetworkError', 'AbortError']
}

/**
 * 全局状态管理
 * @description 管理全局加载状态、请求计数、重试队列、请求缓存等全局状态
 */
let globalLoading = false
let requestCount = 0
const retryQueue = new Map<string, number>()
const requestCache = new Map<string, CacheItem>()
let cacheCleanupTimer: NodeJS.Timeout | null = null

/**
 * 工具函数集合
 * @description 提供各种辅助功能，包括加载状态管理、请求ID生成、缓存键生成等
 */

/**
 * 显示全局加载状态
 * @description 增加请求计数并显示全局加载指示器
 */
const showGlobalLoading = (): void => {
  requestCount++
  if (!globalLoading) {
    globalLoading = true
    console.log('显示全局加载状态')
  }
}

/**
 * 隐藏全局加载状态
 * @description 减少请求计数，当所有请求完成时隐藏全局加载指示器
 */
const hideGlobalLoading = (): void => {
  requestCount--
  if (requestCount <= 0) {
    globalLoading = false
    requestCount = 0
    console.log('隐藏全局加载状态')
  }
}

/**
 * 生成请求唯一标识符
 * @description 根据请求配置生成唯一的请求ID，用于重试队列管理
 * @param config 请求配置
 * @returns 请求ID字符串
 */
const generateRequestId = (config: RequestConfig): string => {
  const { method = 'GET', url, data, params } = config
  const requestData = JSON.stringify({ method, url, data, params })
  return btoa(requestData).replace(/[^a-zA-Z0-9]/g, '')
}

/**
 * 生成缓存键名
 * @description 根据请求配置生成缓存键名，优先使用自定义缓存键，否则根据请求方法和URL生成
 * @param config 请求配置
 * @returns 缓存键名字符串
 */
const generateCacheKey = (config: RequestConfig): string => {
  if (config.cacheKey) {
    return config.cacheKey
  }
  
  const { method = 'GET', url, params } = config
  const queryString = params ? `?${new URLSearchParams(params).toString()}` : ''
  return `${method}_${url}${queryString}`
}

/**
 * 延迟执行函数
 * @description 创建一个指定时间的延迟Promise，用于重试机制中的延迟等待
 * @param ms 延迟时间（毫秒）
 * @returns Promise对象
 */
const delay = (ms: number): Promise<void> => {
  return new Promise(resolve => setTimeout(resolve, ms))
}

/**
 * 判断是否应该重试请求
 * @description 根据错误类型和重试次数判断是否应该重试请求
 * @param error API错误对象
 * @param config 请求配置
 * @returns 是否应该重试
 */
const shouldRetry = (error: ApiError, config: RequestConfig): boolean => {
  const retryCount = config.retryCount || API_CONFIG.DEFAULT_RETRY_COUNT
  const requestId = generateRequestId(config)
  const currentRetry = retryQueue.get(requestId) || 0
  
  if (currentRetry >= retryCount) {
    retryQueue.delete(requestId)
    return false
  }
  
  const isRetryableError = API_CONFIG.RETRYABLE_STATUS_CODES.includes(error.code) ||
                          API_CONFIG.NETWORK_ERROR_TYPES.includes(error.message)
  
  return isRetryableError
}

/**
 * 重试请求
 * @description 使用指数退避策略重试失败的请求
 * @param config 请求配置
 * @param error 原始错误对象
 * @returns 重试后的响应结果
 */
const retryRequest = async (config: RequestConfig, error: ApiError): Promise<ApiResponse> => {
  const requestId = generateRequestId(config)
  const currentRetry = retryQueue.get(requestId) || 0
  const retryDelay = config.retryDelay || API_CONFIG.DEFAULT_RETRY_DELAY
  
  retryQueue.set(requestId, currentRetry + 1)
  
  // 指数退避延迟：每次重试延迟时间翻倍
  const delayTime = retryDelay * Math.pow(2, currentRetry)
  await delay(delayTime)
  
  console.log(`重试请求: ${config.url}, 第${currentRetry + 1}次重试, 延迟${delayTime}ms`)
  
  try {
    const result = await httpRequest(config)
    return result
  } catch (retryError) {
    throw retryError
  }
}

/**
 * 缓存管理模块
 * @description 提供请求缓存的管理功能，包括缓存获取、设置、清理等操作
 */

/**
 * 从缓存中获取数据
 * @description 根据缓存键获取缓存数据，如果缓存过期则自动删除并返回null
 * @param cacheKey 缓存键名
 * @returns 缓存的数据，如果不存在或已过期则返回null
 */
const getCache = (cacheKey: string): any => {
  const cacheItem = requestCache.get(cacheKey)
  
  if (!cacheItem) {
    return null
  }
  
  const now = Date.now()
  if (now > cacheItem.timestamp + cacheItem.expiry) {
    requestCache.delete(cacheKey)
    return null
  }
  
  console.log(`从缓存获取数据: ${cacheKey}`)
  return cacheItem.data
}

/**
 * 设置缓存数据
 * @description 将数据存储到缓存中，包含时间戳和过期时间
 * @param cacheKey 缓存键名
 * @param data 要缓存的数据
 * @param expiry 过期时间（毫秒）
 */
const setCache = (cacheKey: string, data: any, expiry: number): void => {
  const cacheItem: CacheItem = {
    data,
    timestamp: Date.now(),
    expiry
  }
  
  requestCache.set(cacheKey, cacheItem)
  console.log(`设置缓存数据: ${cacheKey}, 过期时间: ${expiry}ms`)
}

/**
 * 清理过期缓存
 * @description 遍历所有缓存项，删除已过期的缓存数据
 */
const cleanupExpiredCache = (): void => {
  const now = Date.now()
  let cleanedCount = 0
  
  for (const [key, item] of requestCache.entries()) {
    if (now > item.timestamp + item.expiry) {
      requestCache.delete(key)
      cleanedCount++
    }
  }
  
  if (cleanedCount > 0) {
    console.log(`清理了 ${cleanedCount} 个过期缓存项`)
  }
}

/**
 * 启动缓存清理定时器
 * @description 启动定时器，每分钟自动清理过期缓存
 */
const startCacheCleanup = (): void => {
  if (cacheCleanupTimer) {
    clearInterval(cacheCleanupTimer)
  }
  
  cacheCleanupTimer = setInterval(cleanupExpiredCache, 60 * 1000)
}

/**
 * 停止缓存清理定时器
 * @description 停止缓存清理定时器，释放资源
 */
const stopCacheCleanup = (): void => {
  if (cacheCleanupTimer) {
    clearInterval(cacheCleanupTimer)
    cacheCleanupTimer = null
  }
}

/**
 * 请求拦截器
 * @description 在发送请求前对请求配置进行处理，包括添加认证token、CSRF token、请求时间戳等
 * @param config 原始请求配置
 * @returns 处理后的请求配置
 */
const requestInterceptor = (config: RequestConfig): RequestConfig => {
  // 添加认证token
  if (isLoggedIn() || isAdminLoggedIn()) {
    const userInfo = isLoggedIn() ? localStorage.getItem('userInfo') : localStorage.getItem('adminUser')
    const token = userInfo ? JSON.parse(userInfo).token : null
    
    if (token) {
      config.headers = {
        ...config.headers,
        'Authorization': `Bearer ${token}`
      }
    }
  }
  
  // 添加请求时间戳
  config.headers = {
    ...config.headers,
    'X-Request-Time': Date.now().toString()
  }
  
  // 添加CSRF token（如果存在）
  const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
  if (csrfToken) {
    config.headers = {
      ...config.headers,
      'X-CSRF-Token': csrfToken
    }
  }
  
  console.log('请求拦截器处理:', {
    url: config.url,
    method: config.method,
    headers: config.headers
  })
  
  return config
}

/**
 * 响应拦截器
 * @description 在接收到响应后对响应数据进行处理，包括状态码检查、业务错误处理等
 * @param response 原始响应对象
 * @param config 请求配置
 * @returns 处理后的响应数据
 */
const responseInterceptor = (response: Response, config: RequestConfig): Promise<ApiResponse> => {
  // 检查HTTP状态码
  if (!response.ok) {
    throw {
      code: response.status,
      message: API_CONFIG.STATUS_MESSAGES[response.status as keyof typeof API_CONFIG.STATUS_MESSAGES] || '请求失败',
      timestamp: Date.now()
    } as ApiError
  }
  
  // 解析响应数据并检查业务状态码
  return response.json().then((data: ApiResponse) => {
    if (data.code !== 200 && data.code !== 0) {
      throw {
        code: data.code,
        message: data.message || '业务处理失败',
        details: data.data,
        timestamp: Date.now()
      } as ApiError
    }
    
    console.log('响应拦截器处理:', {
      url: config.url,
      code: data.code,
      message: data.message
    })
    
    return data
  })
}

/**
 * 错误处理模块
 * @description 统一处理API请求错误，包括重试机制、错误页面跳转、错误消息显示等
 */

/**
 * 统一错误处理器
 * @description 处理所有API请求错误，包括重试、错误页面跳转、错误消息显示等
 * @param error API错误对象
 * @param config 请求配置
 * @returns 永远不会返回，总是抛出错误或重试
 */
const errorHandler = async (error: ApiError, config: RequestConfig): Promise<never> => {
  console.error('请求错误:', error)
  
  // 检查是否需要重试
  if (shouldRetry(error, config)) {
    try {
      const result = await retryRequest(config, error)
      return result as never
    } catch (retryError) {
      error = retryError as ApiError
    }
  }
  
  // 根据错误码跳转到对应的错误页面
  if (error.code === 401) {
    handleAuthError()
    return Promise.reject(error)
  }
  
  if (error.code === 403) {
    // handleErrorRedirect('/403')
    return Promise.reject(error)
  }
  
  if (error.code === 404) {
    // handleErrorRedirect('/404')
    return Promise.reject(error)
  }
  
  if (error.code === 500) {
    // handleErrorRedirect('/500')
    return Promise.reject(error)
  }
  
  // 其他错误码跳转到通用错误页面
  if (error.code >= 400 && error.code < 600) {
    // handleErrorRedirect(`/error/${error.code}`)
    return Promise.reject(error)
  }
  
  // 显示错误消息（如果未禁用）
  if (config.showError !== false) {
    ElMessage.error(error.message || '请求失败')
  }
  
  return Promise.reject(error)
}

/**
 * 处理认证错误
 * @description 当遇到401认证错误时，清除用户登录状态并跳转到登录页面
 */
const handleAuthError = (): void => {
  // 清除所有登录状态
  clearLoginStatus()
  clearAdminLoginStatus()

  // 显示认证失败提示并跳转到登录页面
  ElMessageBox.alert(
    '登录已过期，请重新登录',
    '认证失败',
    {
      confirmButtonText: '确定',
      type: 'warning',
      callback: () => {
        // router.push('/login')
      }
    }
  )
}

/**
 * 处理错误页面跳转
 * @description 根据错误码跳转到对应的错误页面
 * @param path 错误页面路径
 */
const handleErrorRedirect = (path: string): void => {
  // router.push(path)
}

/**
 * 核心HTTP请求函数
 * @description 统一的HTTP请求处理函数，包含缓存检查、请求拦截、响应拦截、错误处理等完整流程
 * @param config 请求配置
 * @returns Promise<ApiResponse<T>> 响应数据
 */
export const httpRequest = async <T = any>(config: RequestConfig): Promise<ApiResponse<T>> => {
  try {
    // 检查缓存（仅GET请求且启用缓存）
    if (config.method === 'GET' && config.enableCache !== false) {
      const cacheKey = generateCacheKey(config)
      const cachedData = getCache(cacheKey)
      
      if (cachedData) {
        console.log(`使用缓存数据: ${cacheKey}`)
        return cachedData
      }
    }
    
    // 显示全局加载状态
    if (config.showLoading !== false) {
      showGlobalLoading()
    }
    
    // 请求拦截处理
    const processedConfig = requestInterceptor(config)
    const url = new URL(processedConfig.url, API_CONFIG.BASE_URL)
    
    // 添加查询参数
    if (processedConfig.params) {
      Object.keys(processedConfig.params).forEach(key => {
        url.searchParams.append(key, processedConfig.params[key])
      })
    }
    
    // 构建fetch配置
    const fetchConfig: RequestInit = {
      method: processedConfig.method || 'GET',
      headers: {
        ...API_CONFIG.HEADERS,
        ...processedConfig.headers
      }
    }
    
    // 添加请求体数据
    if (processedConfig.data && processedConfig.method !== 'GET') {
      fetchConfig.body = JSON.stringify(processedConfig.data)
    }
    
    // 发送请求并处理响应
    const response = await fetch(url.toString(), fetchConfig)
    const result = await responseInterceptor(response, processedConfig)
    
    // 缓存响应数据（仅GET请求且启用缓存）
    if (config.method === 'GET' && config.enableCache !== false) {
      const cacheKey = generateCacheKey(config)
      const cacheExpiry = config.cacheExpiry || API_CONFIG.DEFAULT_CACHE_EXPIRY
      setCache(cacheKey, result, cacheExpiry)
    }
    
    // 隐藏全局加载状态
    if (config.showLoading !== false) {
      hideGlobalLoading()
    }
    
    return result
  } catch (error) {
    // 确保隐藏加载状态
    if (config.showLoading !== false) {
      hideGlobalLoading()
    }
    
    // 错误处理
    return errorHandler(error as ApiError, config)
  }
}

/**
 * 便捷请求方法
 * @description 提供常用的HTTP方法封装，简化API调用
 */

/**
 * GET请求方法
 * @description 发送GET请求，默认启用缓存
 * @param url 请求URL
 * @param params 查询参数
 * @param config 额外配置
 * @returns Promise<ApiResponse<T>>
 */
export const httpGet = <T = any>(
  url: string, 
  params?: any, 
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return httpRequest({
    url,
    method: 'GET',
    params,
    enableCache: true,
    ...config
  })
}

/**
 * POST请求方法
 * @description 发送POST请求，默认禁用缓存
 * @param url 请求URL
 * @param data 请求体数据
 * @param config 额外配置
 * @returns Promise<ApiResponse<T>>
 */
export const httpPost = <T = any>(
  url: string, 
  data?: any, 
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return httpRequest({
    url,
    method: 'POST',
    data,
    enableCache: false,
    ...config
  })
}

/**
 * PUT请求方法
 * @description 发送PUT请求，默认禁用缓存
 * @param url 请求URL
 * @param data 请求体数据
 * @param config 额外配置
 * @returns Promise<ApiResponse<T>>
 */
export const httpPut = <T = any>(
  url: string, 
  data?: any, 
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return httpRequest({
    url,
    method: 'PUT',
    data,
    enableCache: false,
    ...config
  })
}

/**
 * DELETE请求方法
 * @description 发送DELETE请求，默认禁用缓存
 * @param url 请求URL
 * @param config 额外配置
 * @returns Promise<ApiResponse<T>>
 */
export const httpDelete = <T = any>(
  url: string, 
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return httpRequest({
    url,
    method: 'DELETE',
    enableCache: false,
    ...config
  })
}

/**
 * PATCH请求方法
 * @description 发送PATCH请求，默认禁用缓存
 * @param url 请求URL
 * @param data 请求体数据
 * @param config 额外配置
 * @returns Promise<ApiResponse<T>>
 */
export const httpPatch = <T = any>(
  url: string, 
  data?: any, 
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return httpRequest({
    url,
    method: 'PATCH',
    data,
    enableCache: false,
    ...config
  })
}

/**
 * 缓存管理方法
 * @description 提供缓存的手动管理功能，包括清除指定缓存、清除所有缓存、获取缓存统计等
 */

/**
 * 清除指定缓存
 * @description 根据缓存键名清除指定的缓存项
 * @param cacheKey 缓存键名
 */
export const clearCache = (cacheKey: string): void => {
  requestCache.delete(cacheKey)
  console.log(`清除缓存: ${cacheKey}`)
}

/**
 * 清除所有缓存
 * @description 清空所有缓存数据
 */
export const clearAllCache = (): void => {
  requestCache.clear()
  console.log('清除所有缓存')
}

/**
 * 获取缓存统计信息
 * @description 返回缓存的统计信息，包括总数、有效项、过期项等
 * @returns 缓存统计对象
 */
export const getCacheStats = () => {
  const now = Date.now()
  let totalItems = 0
  let expiredItems = 0
  let validItems = 0
  
  for (const [key, item] of requestCache.entries()) {
    totalItems++
    if (now > item.timestamp + item.expiry) {
      expiredItems++
    } else {
      validItems++
    }
  }
  
  return {
    total: totalItems,
    expired: expiredItems,
    valid: validItems,
    size: requestCache.size
  }
}

/**
 * 初始化方法
 * @description 提供HTTP拦截器的初始化和销毁功能
 */

/**
 * 初始化HTTP请求拦截器
 * @description 启动缓存清理定时器，初始化拦截器功能
 */
export const initHttpInterceptor = (): void => {
  startCacheCleanup()
  console.log('HTTP请求拦截器已初始化')
}

/**
 * 销毁HTTP请求拦截器
 * @description 停止缓存清理定时器，清空所有缓存和重试队列
 */
export const destroyHttpInterceptor = (): void => {
  stopCacheCleanup()
  requestCache.clear()
  retryQueue.clear()
  console.log('HTTP请求拦截器已销毁')
}

export default {
  httpRequest,
  httpGet,
  httpPost,
  httpPut,
  httpDelete,
  httpPatch,
  clearCache,
  clearAllCache,
  getCacheStats,
  initHttpInterceptor,
  destroyHttpInterceptor
}

export type { RequestConfig, ApiResponse, ApiError, CacheItem }
